package com.tlgen.orm.utils.orm;

import com.google.common.collect.Lists;
import com.tlgen.orm.support.ModelExecutor;
import com.tlgen.orm.utils.reflect.ReflectionUtils;
import com.tlgen.orm.utils.StringUtils;
import com.tlgen.orm.utils.log.TraceLog;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class BatchUpdateUtils {

    /**
     * 执行批量更新（将多个UPDATE合并为单个SQL）
     *
     * @param models 要更新的实体对象列表
     */
    public static <T> void updateBatch(List<T> models) {
        if (models == null || models.isEmpty()) return;
        T t = models.get(0);
        Class<?> tClass = t.getClass();
        List<List<T>> partitions = Lists.partition(models, 100); // 每批100条
        partitions.forEach(partition -> executeBatchForClass(tClass, partition));
    }
    private static void executeBatchForClass(Class<?> clazz, List<?> models) {
        // 获取表名和主键
        String tableName = ORMUtils.getTableName(clazz);
        String primaryKey = ORMUtils.getPrimaryKey(clazz);

        // 构建批量更新SQL
        String sql = buildBatchUpdateSql(clazz, tableName, primaryKey, models);

        // 执行SQL
        TraceLog.out("Batch Update SQL:\n" + sql);
        ModelExecutor.execute(sql);
    }

    private static String buildBatchUpdateSql(Class<?> clazz, String tableName,
                                              String primaryKey, List<?> models) {
        // 获取所有需要更新的字段（排除主键）
        List<Field> updateFields = ORMUtils.getAllFields(clazz).stream()
                .filter(field -> !field.getName().equals(primaryKey))
                .collect(Collectors.toList());

        // 构建SET子句（每个字段一个CASE表达式）
        String setClause = buildSetClause(updateFields, primaryKey, models);

        // 构建WHERE子句
        String whereClause = buildWhereClause(models, primaryKey);

        return "UPDATE " + tableName + " \nSET\n" +
                setClause + "\n" +
                "WHERE " + primaryKey + " IN (" + whereClause + ")";
    }

    private static String buildSetClause(List<Field> fields, String primaryKey, List<?> models) {
        return fields.stream()
                .map(field -> buildFieldCaseExpression(field, primaryKey, models))
                .collect(Collectors.joining(",\n"));
    }

    private static String buildFieldCaseExpression(Field field, String primaryKey, List<?> models) {
        String fieldName = StringUtils.uncapUnderline(field.getName());
        StringBuilder caseExpr = new StringBuilder();
        caseExpr.append("  ").append(fieldName).append(" = CASE\n");

        for (Object model : models) {
            Object idValue = ReflectionUtils.getFieldValue(model, primaryKey);
            Object fieldValue = ReflectionUtils.getFieldValue(model, field.getName());
            String sqlValue = toSqlValue(fieldValue);

            caseExpr.append("    WHEN ").append(primaryKey).append(" = ").append(idValue)
                    .append(" THEN ").append(sqlValue).append("\n");
        }

        caseExpr.append("    ELSE ").append(fieldName).append("\n")
                .append("  END");

        return caseExpr.toString();
    }

    /**
     * 构建WHERE子句（ID列表）
     */
    private static String buildWhereClause(List<?> models, String primaryKey) {
        return models.stream()
                .map(model -> {
                    Object idValue = ReflectionUtils.getFieldValue(model, primaryKey);
                    return Objects.toString(idValue, "");
                })
                .filter(id -> !id.isEmpty())
                .collect(Collectors.joining(", "));
    }

    /**
     * 将Java值转换为SQL安全值
     */
    private static String toSqlValue(Object value) {
        if (value == null) return "NULL";

        if (value instanceof Number) {
            return value.toString();
        }

        if (value instanceof Boolean) {
            return (Boolean) value ? "1" : "0";
        }

        // 处理字符串和日期：转义单引号
        return "'" + value.toString().replace("'", "''") + "'";
    }

}